# Using Perl's sort

# sort LIST
# sort BLOCK LIST
# sort SUBNAME LIST

# Sorts the LIST and returns the sorted list value 

# The original list is not changed. 

# A sorted list is returned. 


# Ascending lexicographical sorting    
# # sort lexicographically
# @articles = sort @files;

# # same thing, but with explicit sort routine
# @articles = sort {$a cmp $b} @files;

# The default method is about twice as fast as the explicit method. 


# Comparison operators
    
# "<=>" returns -1, 0, or 1 depending on whether the left argument is numerically less than, equal to, or greater than the right argument. 

# "cmp" returns -1, 0, or 1 depending on whether the left argument is stringwise less than, equal to, or greater than the right argument. 


# $a and $b
# $a and $b are two elements of the list being compared during some iteration. 

# To optimize the calling of the sortsub, Perl bypasses the usual passing of arguments via @_, using instead a more efficient special-purpose method. 

# Within the sortsub, the special package global variables $a and $b are aliases for the two operands being compared. 

# The sortsub must return a number less than 0, equal to 0, or greater than 0, depending on the result of comparing the sortkeys of $a and $b. 

# Case matters
# # case-insensitively
# @articles = sort {uc $a  cmp uc $b } @files;

# uc EXPR

# Returns an uppercased version of EXPR 

# Case matters (cont.)


# @sorted = sort { lc $a  cmp lc $b  } @unsorted;
# # or
# @sorted = sort { uc $a  cmp uc $b  } @unsorted;

# There is a difference between these two sortings. 

# There are some punctuation characters that come after upper-case letters and before lower-case characters. 

# Strings that start with such characters would be placed differently in the sorted list, depending on whether we use lc() or uc(). 

# Case matters -- example


# @a=("_a", "a_", "A_", "_A", "Aa", "aA"); 
# map {print $_,"\n";} sort { uc $a cmp uc $b } @a;



# Aa
# aA
# a_
# A_
# _a
# _A



# shlomoyona /usr/lib/perl5 > perl -e '@a=("_a", "a_", "A_", "_A", "Aa", "aA"); map {print $_,"\n";} sort { lc $a cmp lc $b } @a;'



# _a
# _A
# a_
# A_
# Aa
# aA

# Lexicographical sort -- ASCII
# This prints the canonical order of characters used by the cmp, lt, gt, le and ge operators. 


# print +(sort grep /\w/, map { chr } 0 .. 255), "\n";



# 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz

# The map converts the numbers to their ASCII value and the grep gets rid of special characters and the funky control characters that mess up your screen. The plus sign helps Perl interpret the syntax of print correctly. 

# This example shows that, in this case, the expression '_' lt 'a' is TRUE. If your program has the "use locale" pragma, the output order will depend on your current locale. 

# Note that lexicographical sorting is locale depended and that not all platforms use ASCII, at lest one port of Perl uses EBCDIC instead. 



# Descending


# # reversed order
# @articles = sort {$b cmp $a} @files;

# Notice the position of $a and $b 


# Descending (cont.)
# Now, consider this as an alternative solution: 



# @articles = reverse sort @files;

# Note that this is faster than using the explicit descending lexicographic sort 

# Reason: the default sort is faster than using a sortsub. 

# The reverse function is efficient because it just moves pointers around 

# Use reverse if you already have a sorted array instead of resorting it.


# Numerical sort


# # sort numerically ascending
# @articles = sort {$a <=> $b} @files;



# # sort numerically descending
# @articles = sort {$b <=> $a} @files;

# How to sort a hash?
# Internally, hashes are stored in a way that prevents you from imposing an order on key-value pairs. 

# Instead, you have to sort a list of the keys or values: 



# 	@keys = sort keys %hash;    # sorted by key
# 	@keys = sort { $hash{$a} cmp $hash{$b} } keys %hash;       # and by value

# Notice that we compare the values of the hash and save the sorted order of hash keys. 


# Multi-subkey sorts -- sorting by several criteria
# Reverse numeric sort by value, 

# if two keys are identical, sort by length of key, 

# or if that fails, by straight ASCII comparison of the keys 



# @keys = sort {
# 	$hash{$b} <=> $hash{$a}
# 		||
# 	length($b) <=> length($a)
# 		||
# 	$a cmp $b
# } keys %hash;


# Template for multi-subkey sort


# @out = sort {
# 	# primary subkeys comparison
# 	KEY1($a) cmp KEY1($b)
# 		||
# 	# or if they are equal return secondary comparison
# 	# descending numeric comparison
# 	KEY2($b) <=> KEY2($a)
# 		||
# 	# or if they are equal return tertiary comparison
# 	# lexicographic comparison
# 	KEY3($a) cmp KEY3($b)
# } @in;

# KEY() is meant to be substituted with some Perl code that does sortkey extraction. 

# It is best that it not be an actual subroutine call, because subroutine calls within sortsubs can be expensive. 

# Calls to built-in Perl functions (such as the calls to lc in the example above) are like Perl operators, thus less expensive. 

# For more subkeys than 3, you can easily extend the logic...



# Using a subroutine


# # sort using explicit subroutine name
# sub byage {
# 	$age{$a} <=> $age{$b};	# presuming numeric
# }
# @sortedclass = sort byage @class;

# This is the same as 



# # this sorts the %age hash by value instead of key
# # using an in-line function
# @eldest = sort { $age{$b} <=> $age{$a} } keys %age;


# Limitations due to stability
# You should not exit out of the sort block or subroutine using any of the loop control operators described in perlsyn or with goto 

# The special variables $a and $b should never be used to change the values of any input data, as this may break the sort algorithm. 

# Make sure your comparison block/sub is stable. 

